﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Text;
using System.IO;


using Microsoft.SolverFoundation;
using Microsoft.SolverFoundation.Common;
using Microsoft.SolverFoundation.Properties;
using Microsoft.SolverFoundation.Services;
using Microsoft.SolverFoundation.Solvers;

using SchEdu.Framework.Algorithm;
using SchEdu.Framework.DataModel;
using SchEdu.Framework.Exceptions;
using SchEdu.Framework.Validators;

namespace CSP
{
    public class CSPAlgorithm : Algorithm
    {
        string omlModel = @"
            // Job shop scheduling 
            Model[ 
             
              Parameters[Sets,Job,Machine,Task], 
              Parameters[Reals,Time[Job, Machine],TotTime[]], 
              Parameters[Integers,MachNo[Machine],Mach1[Task,Job],Mach2[Task,Job],JobNo[Job]], 
               
              Decisions[Reals[0,Infinity], 
                     x[Job,Machine],  // start time of sub-task 
                     MakeSpan           // total make span of the problem  
              ], 
              // the 0-1 variables deal with overlap 
              Decisions[Integers[0,1],y[Job,Job,Machine]], 
             
              Constraints[ 
             
                // precedence 
                 Foreach[{t,Task},{j,Job}, 
                     FilteredSum[{m2,Machine},MachNo[m2]==Mach2[t,j],x[j,m2]] >= 
                     FilteredSum[{m1,Machine},MachNo[m1]==Mach1[t,j],x[j,m1] + Time[j,m1]] 
                 ], 
             
                 // no overlap 
                 Foreach[{m,Machine},{j,Job}, 
                    FilteredForeach[{k,Job},JobNo[j]<JobNo[k], 
                       x[j,m] >= x[k,m] + Time[k,m] - TotTime[]*y[j,k,m] 
                   ]],          
             
                 Foreach[{m,Machine},{j,Job}, 
                    FilteredForeach[{k,Job},JobNo[j]<JobNo[k], 
                       x[k,m] >= x[j,m] + Time[j,m] - TotTime[]*(1-y[j,k,m]) 
                   ]], 
             
                  // make span 
                  Foreach[{j,Job},{m,Machine}, 
                     MakeSpan >= x[j,m] + Time[j,m] 
                  ] 
              ], 
             
               Goals[Minimize[makespan->MakeSpan]] 

            ]";

        SolverContext solverContext;
        OperationPrecedenceList operationPrecedenceList = new OperationPrecedenceList();
        protected override void Logic()
        {
            solverContext = SolverContext.GetContext();

            solverContext.ClearModel();

            solverContext.LoadModel(FileFormat.OML, new StringReader(omlModel));

            BuildOperationPrecedenceList();

            foreach (Parameter p in solverContext.CurrentModel.Parameters)
            {
                if(p.Name == "Time")
                {
                    p.SetBinding(Operations,"ProcessingTime",new string[]{"OrderID","WorkCenterID"});
                }
                if (p.Name == "MachNo")
                {
                    p.SetBinding(WorkCenters, "ID", new string[]{"ID"});
                }
                if (p.Name == "Mach1")
                {
                    p.SetBinding(operationPrecedenceList, "WorkCenterPredecessorID", new string[] { "OperationID", "OrderID" });
                }
                if (p.Name == "Mach2")
                {
                    p.SetBinding(operationPrecedenceList, "WorkCenterSuccessorID", new string[] { "OperationID", "OrderID" });
                }
                if (p.Name == "JobNo")
                {
                    p.SetBinding(Orders, "ID", new string[] { "ID" });
                }
                if (p.Name == "TotTime")
                {
                    List<TotalTime> t = new List<TotalTime>();
                    TotalTime a = new TotalTime();
                    a.TotTime = Operations.GetProcessingTime();
                    t.Add(a);
                    p.SetBinding(t, "TotTime");
                }
            }

            try
            {
                solverContext.Solve();
            }
            catch(Exception ex)
            {
                ex = ex;
            }
        }

        private void BuildOperationPrecedenceList()
        {
            operationPrecedenceList = new OperationPrecedenceList();
            foreach (SchEduDataSet.OrderRow order in SchEduData.Order)
            {
                SchEduDataSet.OperationRow previousOperation = null;
                OperationList operations = new OperationList(order.GetOperationRows());
                operations.SortBySequenceNo();
                foreach (SchEduDataSet.OperationRow operation in operations)
                {
                    if (previousOperation == null)
                    {
                        previousOperation = operation;
                        continue;
                    }
                    OperationPrecedence op = new OperationPrecedence();
                    op.WorkCenterPredecessorID = previousOperation.WorkCenterID;
                    op.WorkCenterSuccessorID = operation.WorkCenterID;
                    op.OrderID = operation.OrderID;
                    op.OperationID = operation.ID;
                    operationPrecedenceList.Add(op);
                    previousOperation = operation;

                    this.Logger.Debug(string.Format("Mach1:{0} Mach2:{1} Job:{2} Task:{3}",
                        op.WorkCenterPredecessorID,op.WorkCenterSuccessorID,op.OrderID,op.OperationID));
                }
            }
        }
        public override AboutInfo AboutInfo
        {
            get
            {
                AboutInfo aboutInfo = new AboutInfo();
                aboutInfo.Title = "CSP";
                aboutInfo.Description = @"";
                aboutInfo.Guid = new Guid("{5C717E89-86CD-45e2-A514-66D4822F1C9F}");
                return aboutInfo;
            }
        }


    }

    public class TotalTime
    {
        int totTime;

        public int TotTime
        {
          get { return totTime; }
          set { totTime = value; }
        }
    }

    public class OperationPrecedence
    {
        int orderID;

        public int OrderID
        {
            get { return orderID; }
            set { orderID = value; }
        }
        int operationID;

        public int OperationID
        {
            get { return operationID; }
            set { operationID = value; }
        }
        int workCenterPredecessorID;

        public int WorkCenterPredecessorID
        {
            get { return workCenterPredecessorID; }
            set { workCenterPredecessorID = value; }
        }
        int workCenterSuccessorID;

        public int WorkCenterSuccessorID
        {
            get { return workCenterSuccessorID; }
            set { workCenterSuccessorID = value; }
        }
    }

    public class OperationPrecedenceList : List<OperationPrecedence>
    {
    }
}
